home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 4: GNU Archives / Linux Cubed Series 4 - GNU Archives.iso / gnu / glibc-1.09 / glibc-1 / glibc-1.09.1 / resolv / res_send.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-07-28  |  18.6 KB  |  758 lines

  1. /*
  2.  * ++Copyright++ 1985, 1989, 1993
  3.  * -
  4.  * Copyright (c) 1985, 1989, 1993
  5.  *    The Regents of the University of California.  All rights reserved.
  6.  * 
  7.  * Redistribution and use in source and binary forms, with or without
  8.  * modification, are permitted provided that the following conditions
  9.  * are met:
  10.  * 1. Redistributions of source code must retain the above copyright
  11.  *    notice, this list of conditions and the following disclaimer.
  12.  * 2. Redistributions in binary form must reproduce the above copyright
  13.  *    notice, this list of conditions and the following disclaimer in the
  14.  *    documentation and/or other materials provided with the distribution.
  15.  * 3. All advertising materials mentioning features or use of this software
  16.  *    must display the following acknowledgement:
  17.  *     This product includes software developed by the University of
  18.  *     California, Berkeley and its contributors.
  19.  * 4. Neither the name of the University nor the names of its contributors
  20.  *    may be used to endorse or promote products derived from this software
  21.  *    without specific prior written permission.
  22.  * 
  23.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  24.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  25.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  26.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  27.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  28.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  29.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  30.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  31.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  32.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  33.  * SUCH DAMAGE.
  34.  * -
  35.  * Portions Copyright (c) 1993 by Digital Equipment Corporation.
  36.  * 
  37.  * Permission to use, copy, modify, and distribute this software for any
  38.  * purpose with or without fee is hereby granted, provided that the above
  39.  * copyright notice and this permission notice appear in all copies, and that
  40.  * the name of Digital Equipment Corporation not be used in advertising or
  41.  * publicity pertaining to distribution of the document or software without
  42.  * specific, written prior permission.
  43.  * 
  44.  * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
  45.  * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
  46.  * OF MERCHANTABILITY AND FITNESS.   IN NO EVENT SHALL DIGITAL EQUIPMENT
  47.  * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
  48.  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
  49.  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
  50.  * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
  51.  * SOFTWARE.
  52.  * -
  53.  * --Copyright--
  54.  */
  55.  
  56. #if defined(LIBC_SCCS) && !defined(lint)
  57. static char sccsid[] = "@(#)res_send.c    8.1 (Berkeley) 6/4/93";
  58. static char rcsid[] = "$Id: res_send.c,v 1.2 1994/07/28 21:56:28 roland Exp $";
  59. #endif /* LIBC_SCCS and not lint */
  60.  
  61.     /* change this to "0"
  62.      * if you talk to a lot
  63.      * of multi-homed SunOS
  64.      * ("broken") name servers.
  65.      */
  66. #define    CHECK_SRVR_ADDR    1    /* XXX - should be in options.h */
  67.  
  68. /*
  69.  * Send query to name server and wait for reply.
  70.  */
  71.  
  72. #include <sys/param.h>
  73. #include <sys/time.h>
  74. #include <sys/socket.h>
  75. #include <sys/uio.h>
  76. #include <netinet/in.h>
  77. #include <arpa/nameser.h>
  78. #include <arpa/inet.h>
  79.  
  80. #include <stdio.h>
  81. #include <errno.h>
  82. #include <resolv.h>
  83. #if defined(BSD) && (BSD >= 199306)
  84. # include <stdlib.h>
  85. # include <string.h>
  86. #else
  87. # include "../conf/portability.h"
  88. #endif
  89.  
  90. #if defined(USE_OPTIONS_H)
  91. # include <../conf/options.h>
  92. #endif
  93.  
  94. void _res_close __P((void));
  95.  
  96. static int s = -1;    /* socket used for communications */
  97. static int connected = 0;    /* is the socket connected */
  98. static int vc = 0;    /* is the socket a virtual ciruit? */
  99.  
  100. #ifndef FD_SET
  101. /* XXX - should be in portability.h */
  102. #define    NFDBITS        32
  103. #define    FD_SETSIZE    32
  104. #define    FD_SET(n, p)    ((p)->fds_bits[(n)/NFDBITS] |= (1 << ((n) % NFDBITS)))
  105. #define    FD_CLR(n, p)    ((p)->fds_bits[(n)/NFDBITS] &= ~(1 << ((n) % NFDBITS)))
  106. #define    FD_ISSET(n, p)    ((p)->fds_bits[(n)/NFDBITS] & (1 << ((n) % NFDBITS)))
  107. #define FD_ZERO(p)    bzero((char *)(p), sizeof(*(p)))
  108. #endif
  109.  
  110. #ifndef DEBUG
  111. #   define Dprint(cond, args) /*empty*/
  112. #   define DprintQ(cond, args, query) /*empty*/
  113. #   define Aerror(file, string, error, address) /*empty*/
  114. #   define Perror(file, string, error) /*empty*/
  115. #else
  116. #   define Dprint(cond, args) if (cond) {fprintf args;} else {}
  117. #   define DprintQ(cond, args, query) if (cond) {\
  118.             fprintf args;\
  119.             __p_query(query);\
  120.         } else {}
  121.     static void
  122.     Aerror(file, string, error, address)
  123.     FILE *file;
  124.     char *string;
  125.     int error;
  126.     struct sockaddr_in address;
  127.     {
  128.     int save = errno;
  129.  
  130.     if (_res.options & RES_DEBUG) {
  131.         fprintf(file, "res_send: %s ([%s].%d): %s\n",
  132.             string,
  133.             inet_ntoa(address.sin_addr),
  134.             address.sin_port,
  135.             strerror(error));
  136.     }
  137.     errno = save;
  138.     }
  139.     static void
  140.     Perror(file, string, error)
  141.     FILE *file;
  142.     char *string;
  143.     int error;
  144.     {
  145.     int save = errno;
  146.  
  147.     if (_res.options & RES_DEBUG) {
  148.         fprintf(file, "res_send: %s: %s\n",
  149.             string, strerror(error));
  150.     }
  151.     errno = save;
  152.     }
  153. #endif
  154.  
  155. static res_send_qhook Qhook = NULL;
  156. static res_send_rhook Rhook = NULL;
  157.  
  158. void
  159. res_send_setqhook(hook)
  160.     res_send_qhook hook;
  161. {
  162.     Qhook = hook;
  163. }
  164.  
  165. void
  166. res_send_setrhook(hook)
  167.     res_send_rhook hook;
  168. {
  169.     Rhook = hook;
  170. }
  171.  
  172. /* int
  173.  * our_server(ina)
  174.  *    looks up "ina" in _res.ns_addr_list[]
  175.  * returns:
  176.  *    0  : not found
  177.  *    >0 : found
  178.  * author:
  179.  *    paul vixie, 29may94
  180.  */
  181. static int
  182. our_server(inp)
  183.     const struct sockaddr_in *inp;
  184. {
  185.     struct sockaddr_in ina;
  186.     register int ns, ret;
  187.  
  188.     ina = *inp;
  189.     ret = 0;
  190.     for (ns = 0;  ns < _res.nscount;  ns++) {
  191.         register const struct sockaddr_in *srv = &_res.nsaddr_list[ns];
  192.  
  193.         if (srv->sin_family == ina.sin_family &&
  194.             srv->sin_port == ina.sin_port &&
  195.             (srv->sin_addr.s_addr == INADDR_ANY ||
  196.              srv->sin_addr.s_addr == ina.sin_addr.s_addr)) {
  197.             ret++;
  198.             break;
  199.         }
  200.     }
  201.     return (ret);
  202. }
  203.  
  204. /* int
  205.  * name_in_query(name, type, class, buf, eom)
  206.  *    look for (name,type,class) in the query section of packet (buf,eom)
  207.  * returns:
  208.  *    -1 : format error
  209.  *    0  : not found
  210.  *    >0 : found
  211.  */
  212. static int
  213. name_in_query(name, type, class, buf, eom)
  214.     const char *name;
  215.     register int type, class;
  216.     const u_char *buf, *eom;
  217. {
  218.     register const u_char *cp = buf + HFIXEDSZ;
  219.     int qdcount = ntohs(((HEADER*)buf)->qdcount);
  220.  
  221.     while (qdcount-- > 0) {
  222.         char tname[MAXDNAME+1];
  223.         register int n, ttype, tclass;
  224.  
  225.         n = dn_expand(buf, eom, cp, tname, sizeof tname);
  226.         if (n < 0)
  227.             return (-1);
  228.         cp += n;
  229.         ttype = _getshort(cp);    cp += INT16SZ;
  230.         tclass = _getshort(cp); cp += INT16SZ;
  231.         if (ttype == type &&
  232.             tclass == class &&
  233.             strcasecmp(tname, name) == 0)
  234.             return (1);
  235.     }
  236.     return (0);
  237. }
  238.  
  239. /* int
  240.  * queries_match(buf1, eom1, buf2, eom2)
  241.  *    is there a 1:1 mapping of (name,type,class)
  242.  *    in (buf1,eom1) and (buf2,eom2)?
  243.  * returns:
  244.  *    -1 : format error
  245.  *    0  : not a 1:1 mapping
  246.  *    >0 : is a 1:1 mapping
  247.  */
  248. static int
  249. queries_match(buf1, eom1, buf2, eom2)
  250.     const u_char *buf1, *eom1;
  251.     const u_char *buf2, *eom2;
  252. {
  253.     register const u_char *cp = buf1 + HFIXEDSZ;
  254.     int qdcount = ntohs(((HEADER*)buf1)->qdcount);
  255.  
  256.     if (qdcount != ntohs(((HEADER*)buf2)->qdcount))
  257.         return (0);
  258.     while (qdcount-- > 0) {
  259.         char tname[MAXDNAME+1];
  260.         register int n, ttype, tclass;
  261.  
  262.         n = dn_expand(buf1, eom1, cp, tname, sizeof tname);
  263.         if (n < 0)
  264.             return (-1);
  265.         cp += n;
  266.         ttype = _getshort(cp);    cp += INT16SZ;
  267.         tclass = _getshort(cp); cp += INT16SZ;
  268.         if (!name_in_query(tname, ttype, tclass, buf2, eom2))
  269.             return (0);
  270.     }
  271.     return (1);
  272. }
  273.  
  274. int
  275. res_send(buf, buflen, ans, anssiz)
  276.     const u_char    *buf;
  277.     int        buflen;
  278.     u_char        *ans;
  279.     int        anssiz;
  280. {
  281.     HEADER        *hp = (HEADER *) buf;
  282.     HEADER        *anhp = (HEADER *) ans;
  283.     int        gotsomewhere = 0,
  284.             connreset = 0,
  285.             terrno = ETIMEDOUT;
  286.  
  287.     register int    n;
  288.     int        try, v_circuit, resplen, ns;
  289.     u_int        badns;    /* XXX NSMAX can't exceed #/bits in this var */
  290.  
  291.     DprintQ((_res.options & RES_DEBUG) || (_res.pfcode & RES_PRF_QUERY),
  292.         (stdout, ";; res_send()\n"), buf);
  293.     if (!(_res.options & RES_INIT)) {
  294.         if (res_init() == -1)
  295.             return (-1);
  296.     }
  297.     v_circuit = (_res.options & RES_USEVC) || buflen > PACKETSZ;
  298.     badns = 0;
  299.  
  300.     /*
  301.      * Send request, RETRY times, or until successful
  302.      */
  303.     for (try = 0; try < _res.retry; try++) {
  304.         for (ns = 0; ns < _res.nscount; ns++) {
  305.         struct sockaddr_in *nsap = &_res.nsaddr_list[ns];
  306.     same_ns:
  307.         if (badns & (1<<ns)) {
  308.             _res_close();
  309.             goto next_ns;
  310.         }
  311.  
  312.         if (Qhook) {
  313.             int done = 0, loops = 0;
  314.  
  315.             do {
  316.                 res_sendhookact act;
  317.  
  318.                 act = (*Qhook)(&nsap,
  319.                            &buf,
  320.                            &buflen,
  321.                            ans,
  322.                            anssiz,
  323.                            &resplen);
  324.                 switch (act) {
  325.                 case res_goahead:
  326.                     done = 1;
  327.                     break;
  328.                 case res_nextns:
  329.                     _res_close();
  330.                     goto next_ns;
  331.                 case res_done:
  332.                     return (resplen);
  333.                 case res_modified:
  334.                     /* give the hook another try */
  335.                     if (++loops < 42) /*doug adams*/
  336.                         break;
  337.                     /*FALLTHROUGH*/
  338.                 case res_error:
  339.                     /*FALLTHROUGH*/
  340.                 default:
  341.                     return (-1);
  342.                 }
  343.             } while (!done);
  344.         }
  345.  
  346.         Dprint(_res.options & RES_DEBUG,
  347.                (stdout, ";; Querying server (# %d) address = %s\n",
  348.             ns+1, inet_ntoa(nsap->sin_addr)));
  349.  
  350.         if (v_circuit) {
  351.             int        truncated;
  352.             struct iovec    iov[2];
  353.             u_short        len;
  354.             u_char        *cp;
  355.  
  356.             /*
  357.              * Use virtual circuit;
  358.              * at most one attempt per server.
  359.              */
  360.             try = _res.retry;
  361.             truncated = 0;
  362.             if ((s < 0) || (!vc)) {
  363.                 if (s >= 0)
  364.                     _res_close();
  365.  
  366.                 s = socket(AF_INET, SOCK_STREAM, PF_UNSPEC);
  367.                 if (s < 0) {
  368.                     terrno = errno;
  369.                     Perror(stderr, "socket(vc)", errno);
  370.                     return (-1);
  371.                 }
  372.                 if (connect(s,
  373.                         (struct sockaddr *)nsap,
  374.                         sizeof(struct sockaddr))
  375.                     < 0) {
  376.                     terrno = errno;
  377.                     Aerror(stderr, "connect/vc",
  378.                            errno, *nsap);
  379.                     badns |= (1<<ns);
  380.                     _res_close();
  381.                     goto next_ns;
  382.                 }
  383.                 vc = 1;
  384.             }
  385.             /*
  386.              * Send length & message
  387.              */
  388.             putshort((u_short)buflen, (u_char*)&len);
  389.             iov[0].iov_base = (caddr_t)&len;
  390.             iov[0].iov_len = INT16SZ;
  391.             iov[1].iov_base = (caddr_t)buf;
  392.             iov[1].iov_len = buflen;
  393.             if (writev(s, iov, 2) != (INT16SZ + buflen)) {
  394.                 terrno = errno;
  395.                 Perror(stderr, "write failed", errno);
  396.                 badns |= (1<<ns);
  397.                 _res_close();
  398.                 goto next_ns;
  399.             }
  400.             /*
  401.              * Receive length & response
  402.              */
  403.             cp = ans;
  404.             len = INT16SZ;
  405.             while ((n = read(s, (char *)cp, (int)len)) > 0) {
  406.                 cp += n;
  407.                 if ((len -= n) <= 0)
  408.                     break;
  409.             }
  410.             if (n <= 0) {
  411.                 terrno = errno;
  412.                 Perror(stderr, "read failed", errno);
  413.                 _res_close();
  414.                 /*
  415.                  * A long running process might get its TCP
  416.                  * connection reset if the remote server was
  417.                  * restarted.  Requery the server instead of
  418.                  * trying a new one.  When there is only one
  419.                  * server, this means that a query might work
  420.                  * instead of failing.  We only allow one reset
  421.                  * per query to prevent looping.
  422.                  */
  423.                 if (terrno == ECONNRESET && !connreset) {
  424.                     connreset = 1;
  425.                     _res_close();
  426.                     goto same_ns;
  427.                 }
  428.                 _res_close();
  429.                 goto next_ns;
  430.             }
  431.             resplen = _getshort(ans);
  432.             if (resplen > anssiz) {
  433.                 Dprint(_res.options & RES_DEBUG,
  434.                        (stdout, ";; response truncated\n")
  435.                        );
  436.                 truncated = 1;
  437.                 len = anssiz;
  438.             } else
  439.                 len = resplen;
  440.             cp = ans;
  441.             while (len != 0 &&
  442.                    (n = read(s, (char *)cp, (int)len)) > 0
  443.                    ) {
  444.                 cp += n;
  445.                 len -= n;
  446.             }
  447.             if (n <= 0) {
  448.                 terrno = errno;
  449.                 Perror(stderr, "read(vc)", errno);
  450.                 _res_close();
  451.                 goto next_ns;
  452.             }
  453.             if (truncated) {
  454.                 /*
  455.                  * Flush rest of answer
  456.                  * so connection stays in synch.
  457.                  */
  458.                 anhp->tc = 1;
  459.                 len = resplen - anssiz;
  460.                 while (len != 0) {
  461.                     char junk[512];
  462.  
  463.                     n = (len > sizeof(junk)
  464.                          ? sizeof(junk)
  465.                          : len);
  466.                     if ((n = read(s, junk, n)) > 0)
  467.                         len -= n;
  468.                     else
  469.                         break;
  470.                 }
  471.             }
  472.         } else {
  473.             /*
  474.              * Use datagrams.
  475.              */
  476.             struct timeval    timeout;
  477.             fd_set        dsmask;
  478.             struct sockaddr_in from;
  479.             int        fromlen;
  480.  
  481.             if ((s < 0) || vc) {
  482.                 if (vc)
  483.                     _res_close();
  484.                 s = socket(AF_INET, SOCK_DGRAM, PF_UNSPEC);
  485.                 if (s < 0) {
  486.  bad_dg_sock:                terrno = errno;
  487.                     Perror(stderr, "socket(dg)", errno);
  488.                     return (-1);
  489.                 }
  490.                 connected = 0;
  491.             }
  492.             /*
  493.              * On a 4.3BSD+ machine (client and server,
  494.              * actually), sending to a nameserver datagram
  495.              * port with no nameserver will cause an
  496.              * ICMP port unreachable message to be returned.
  497.              * If our datagram socket is "connected" to the
  498.              * server, we get an ECONNREFUSED error on the next
  499.              * socket operation, and select returns if the
  500.              * error message is received.  We can thus detect
  501.              * the absence of a nameserver without timing out.
  502.              * If we have sent queries to at least two servers,
  503.              * however, we don't want to remain connected,
  504.              * as we wish to receive answers from the first
  505.              * server to respond.
  506.              */
  507.             if (_res.nscount == 1 || (try == 0 && ns == 0)) {
  508.                 /*
  509.                  * Connect only if we are sure we won't
  510.                  * receive a response from another server.
  511.                  */
  512.                 if (!connected) {
  513.                     if (connect(s,
  514.                             (struct sockaddr *)nsap,
  515.                             sizeof(struct sockaddr)
  516.                             ) < 0
  517.                         ) {
  518.                         Aerror(stderr,
  519.                                "connect(dg)",
  520.                                errno, *nsap);
  521.                         badns |= (1<<ns);
  522.                         _res_close();
  523.                         goto next_ns;
  524.                     }
  525.                     connected = 1;
  526.                 }
  527.                 if (send(s, buf, buflen, 0) != buflen) {
  528.                     Perror(stderr, "send", errno);
  529.                     badns |= (1<<ns);
  530.                     _res_close();
  531.                     goto next_ns;
  532.                 }
  533.             } else {
  534.                 /*
  535.                  * Disconnect if we want to listen
  536.                  * for responses from more than one server.
  537.                  */
  538.                 if (connected) {
  539. #if defined(BSD) && (BSD >= 199103)
  540.                     struct sockaddr_in no_addr;
  541.  
  542.                     no_addr.sin_family = AF_INET;
  543.                     no_addr.sin_addr.s_addr = INADDR_ANY;
  544.                     no_addr.sin_port = 0;
  545.                     (void) connect(s,
  546.                                (struct sockaddr *)
  547.                                 &no_addr,
  548.                                sizeof(no_addr));
  549. #else
  550.                     int s1 = socket(AF_INET, SOCK_DGRAM,
  551.                             PF_UNSPEC);
  552.                     if (s1 < 0)
  553.                         goto bad_dg_sock;
  554.                     (void) dup2(s1, s);
  555.                     (void) close(s1);
  556.                     Dprint(_res.options & RES_DEBUG,
  557.                            (stdout, ";; new DG socket\n"))
  558. #endif
  559.                     connected = 0;
  560.                     errno = 0;
  561.                 }
  562.                 if (sendto(s, buf, buflen, 0,
  563.                        (struct sockaddr *)nsap,
  564.                        sizeof(struct sockaddr))
  565.                     != buflen) {
  566.                     Aerror(stderr, "sendto", errno, *nsap);
  567.                     badns |= (1<<ns);
  568.                     _res_close();
  569.                     goto next_ns;
  570.                 }
  571.             }
  572.  
  573.             /*
  574.              * Wait for reply
  575.              */
  576.             timeout.tv_sec = (_res.retrans << try);
  577.             if (try > 0)
  578.                 timeout.tv_sec /= _res.nscount;
  579.             if ((long) timeout.tv_sec <= 0)
  580.                 timeout.tv_sec = 1;
  581.             timeout.tv_usec = 0;
  582.     wait:
  583.             FD_ZERO(&dsmask);
  584.             FD_SET(s, &dsmask);
  585.             n = select(s+1, &dsmask, (fd_set *)NULL,
  586.                    (fd_set *)NULL, &timeout);
  587.             if (n < 0) {
  588.                 Perror(stderr, "select", errno);
  589.                 _res_close();
  590.                 goto next_ns;
  591.             }
  592.             if (n == 0) {
  593.                 /*
  594.                  * timeout
  595.                  */
  596.                 Dprint(_res.options & RES_DEBUG,
  597.                        (stdout, ";; timeout\n")
  598.                        );
  599.                 gotsomewhere = 1;
  600.                 _res_close();
  601.                 goto next_ns;
  602.             }
  603.             fromlen = sizeof(struct sockaddr_in);
  604.             resplen = recvfrom(s, ans, anssiz, 0,
  605.                        (struct sockaddr *)&from, &fromlen);
  606.             if (resplen <= 0) {
  607.                 Perror(stderr, "recvfrom", errno);
  608.                 _res_close();
  609.                 goto next_ns;
  610.             }
  611.             gotsomewhere = 1;
  612.             if (hp->id != anhp->id) {
  613.                 /*
  614.                  * response from old query, ignore it.
  615.                  * XXX - potential security hazard could
  616.                  *     be detected here.
  617.                  */
  618.                 DprintQ((_res.options & RES_DEBUG) ||
  619.                     (_res.pfcode & RES_PRF_REPLY),
  620.                     (stdout, ";; old answer:\n"),
  621.                     ans);
  622.                 goto wait;
  623.             }
  624. #if CHECK_SRVR_ADDR
  625.             if (!(_res.options & RES_INSECURE1) &&
  626.                 !our_server(&from)) {
  627.                 /*
  628.                  * response from wrong server? ignore it.
  629.                  * XXX - potential security hazard could
  630.                  *     be detected here.
  631.                  */
  632.                 DprintQ((_res.options & RES_DEBUG) ||
  633.                     (_res.pfcode & RES_PRF_REPLY),
  634.                     (stdout, ";; not our server:\n"),
  635.                     ans);
  636.                 goto wait;
  637.             }
  638. #endif
  639.             if (!(_res.options & RES_INSECURE2) &&
  640.                 !queries_match(buf, buf + buflen,
  641.                        ans, ans + anssiz)) {
  642.                 /*
  643.                  * response contains wrong query? ignore it.
  644.                  * XXX - potential security hazard could
  645.                  *     be detected here.
  646.                  */
  647.                 DprintQ((_res.options & RES_DEBUG) ||
  648.                     (_res.pfcode & RES_PRF_REPLY),
  649.                     (stdout, ";; wrong query name:\n"),
  650.                     ans);
  651.                 goto wait;
  652.             }
  653.             if (anhp->rcode == SERVFAIL ||
  654.                 anhp->rcode == NOTIMP ||
  655.                 anhp->rcode == REFUSED) {
  656.                 DprintQ(_res.options & RES_DEBUG,
  657.                     (stdout, "server rejected query:\n"),
  658.                     ans);
  659.                 badns |= (1<<ns);
  660.                 _res_close();
  661.                 goto next_ns;
  662.             }
  663.             if (!(_res.options & RES_IGNTC) && anhp->tc) {
  664.                 /*
  665.                  * get rest of answer;
  666.                  * use TCP with same server.
  667.                  */
  668.                 Dprint(_res.options & RES_DEBUG,
  669.                        (stdout, ";; truncated answer\n")
  670.                        );
  671.                 v_circuit = 1;
  672.                 _res_close();
  673.                 goto same_ns;
  674.             }
  675.         } /*if vc/dg*/
  676.         DprintQ((_res.options & RES_DEBUG) ||
  677.             (_res.pfcode & RES_PRF_REPLY),
  678.             (stdout, ";; got answer:\n"),
  679.             ans);
  680.         /*
  681.          * If using virtual circuits, we assume that the first server
  682.          * is preferred over the rest (i.e. it is on the local
  683.          * machine) and only keep that one open.
  684.          * If we have temporarily opened a virtual circuit,
  685.          * or if we haven't been asked to keep a socket open,
  686.          * close the socket.
  687.          */
  688.         if ((v_circuit && (!(_res.options & RES_USEVC) || ns != 0)) ||
  689.             !(_res.options & RES_STAYOPEN)) {
  690.             _res_close();
  691.         }
  692.         if (Rhook) {
  693.             int done = 0, loops = 0;
  694.  
  695.             do {
  696.                 res_sendhookact act;
  697.  
  698.                 act = (*Rhook)(nsap,
  699.                            buf,
  700.                            buflen,
  701.                            ans,
  702.                            anssiz,
  703.                            &resplen);
  704.                 switch (act) {
  705.                 case res_goahead:
  706.                 case res_done:
  707.                     done = 1;
  708.                     break;
  709.                 case res_nextns:
  710.                     _res_close();
  711.                     goto next_ns;
  712.                 case res_modified:
  713.                     /* give the hook another try */
  714.                     if (++loops < 42) /*doug adams*/
  715.                         break;
  716.                     /*FALLTHROUGH*/
  717.                 case res_error:
  718.                     /*FALLTHROUGH*/
  719.                 default:
  720.                     return (-1);
  721.                 }
  722.             } while (!done);
  723.  
  724.         }
  725.         return (resplen);
  726.     next_ns: ;
  727.        } /*foreach ns*/
  728.     } /*foreach retry*/
  729.     _res_close();
  730.     if (!v_circuit) {
  731.         if (!gotsomewhere)
  732.             errno = ECONNREFUSED;    /* no nameservers found */
  733.         else
  734.             errno = ETIMEDOUT;    /* no answer obtained */
  735.     } else {
  736.         errno = terrno;
  737.     }
  738.     return (-1);
  739. }
  740.  
  741. /*
  742.  * This routine is for closing the socket if a virtual circuit is used and
  743.  * the program wants to close it.  This provides support for endhostent()
  744.  * which expects to close the socket.
  745.  *
  746.  * This routine is not expected to be user visible.
  747.  */
  748. void
  749. _res_close()
  750. {
  751.     if (s >= 0) {
  752.         (void) close(s);
  753.         s = -1;
  754.         connected = 0;
  755.         vc = 0;
  756.     }
  757. }
  758.